import time

import keras.backend
from keras.applications.vgg16 import VGG16
from keras.utils import image_utils
from keras.applications.vgg16 import preprocess_input, decode_predictions
from keras import backend as k
import numpy as np
import cv2
import tensorflow as tf

# 运行程序出错，百度后添加
from matplotlib import pyplot as plt

tf.compat.v1.disable_eager_execution()

# 网络中包括了密集连接分类器
model = VGG16(weights='imagenet')
'''
可视化类激活的热力图
'''

# 测试图片路径
img_path = r'D:\Users\kk\PycharmProjects\pythonProject\pythonProject2\tt\demo02\image\ad.jpg'
# 大小为224×224的Python图像库（PIL, Python imageing library）图像
img = image_utils.load_img(img_path, target_size=(224, 224))
# 形状为（224， 224， 3）的float32格式的Numpy数组
x = image_utils.img_to_array(img)
# 添加一个维度， 将数组转换为（1，224，224，3）形状的批量
x = np.expand_dims(x, axis=0) # axis(数组层级，沿着i轴变化)

# 对批量进行预处理（按通道进行颜色标准化）
x = preprocess_input(x)
# 输出预测属性
preds = model.predict(x)
print('Predicted:',decode_predictions(preds, top=3)[0])
# 输出预测元素索引编号386
print(np.argmax(preds[0]))

# 预测向量中‘非洲象’元素
african_elephant_output = model.output[:,np.argmax(preds[0])]
# block5_conv3层的输出特征图，它是VGG16的最后一个卷积层
last_conv_layer = model.get_layer('block5_conv3')


# 输出特征图的梯度
grads = k.gradients(african_elephant_output, last_conv_layer.output)[0]
# 形状为（512，）的向量，每个元素是特定特征图通道的梯度平均大小
pooled_grads = k.mean(grads, axis=(0, 1, 2))
# 访问刚刚定义的量：对于给定的样本图像， pooled_grads和block_conv3层的输出特征图
iterate = k.function([model.input], [pooled_grads, last_conv_layer.output[0]])
# 对于两个大象的样本图像，这两个量都是Numpy数组
pooled_grads_value, conv_layer_output_value = iterate([x])
# 将特征图数组的每个通道乘以“这个通道对‘大象’类别的重要程度”
for i in range(512):
    conv_layer_output_value[:, :, i] *= pooled_grads_value[i]
# 得到的特征图的逐通道平均值即为类激活的热力图
#   axis=0(计算每列均值) axis=1或-1(计算每行均值) 不带参数，计算总均值
heatmap = np.mean(conv_layer_output_value, axis=-1)
'''
热力图后处理
'''
# 逐元素比较，输出最大值
heatmap = np.maximum(heatmap, 0)
# 除以元素中的最大值
heatmap /= np.max(heatmap)
# # 将元素列为颜色矩阵
# plt.matshow(heatmap)
# plt.show()

'''
将热力图与原始图像叠加
'''
# 处理图片为3维元素
img = cv2.imread(img_path)
# 将热力图大小调整为与原始图像相同
# shape属性（584乘389像素的三维图片）
heatmap = cv2.resize(heatmap, (img.shape[1], img.shape[0]))
print(heatmap)
# 元素取整
heatmap = np.uint8(255 * heatmap)
print(heatmap)
heatmap = cv2.applyColorMap(heatmap, cv2.COLORMAP_JET)
# 弱化热力图强度，0.4是热力图强度因子
superimposed_img =img  + heatmap * 0.4

# 窗口显示热力图
cv2.imshow('sds',superimposed_img/255)
# # 生成热力图图片
# cv2.imwrite('cc.jpg',superimposed_img)
# 等待输入0按键
cv2.waitKey(0)
